package jmine.tec.web.front.workflow;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import jmine.tec.web.front.FrontException;
import jmine.tec.web.front.FrontMessages;
import jmine.tec.web.front.dao.BackOfficeRequestStatusSystemIdentifier;
import jmine.tec.web.front.domain.BackOfficeRequestRevisionOutcome;

/**
 * Represents a status workflow.
 * 
 * @author wagner.tsuchiya
 */
public class BackOfficeRequestStatusWorkflow {
    private final List<BackOfficeRequestStatusVertex> vertices = new ArrayList<BackOfficeRequestStatusVertex>();

    private Map<BackOfficeRequestStatusSystemIdentifier, BackOfficeRequestStatusVertex> statusMap = null;

    private final BackOfficeRequestStatusSystemIdentifier rootStatus;

    /**
     * Construtor.
     * 
     * @param rootStatus BackOfficeRequestStatusSystemIdentifier
     */
    public BackOfficeRequestStatusWorkflow(BackOfficeRequestStatusSystemIdentifier rootStatus) {
        this.rootStatus = rootStatus;
    }

    /**
     * Adds a new vertex.
     * 
     * @param vertex vertex.
     */
    public void addVertex(BackOfficeRequestStatusVertex vertex) {
        if (this.statusMap != null) {
            this.statusMap = null;
        }
        this.vertices.add(vertex);
    }

    /**
     * @return a map from system identifier to the vertex.
     */
    private Map<BackOfficeRequestStatusSystemIdentifier, BackOfficeRequestStatusVertex> getStatusMap() {
        if (this.statusMap == null) {
            this.statusMap = new HashMap<BackOfficeRequestStatusSystemIdentifier, BackOfficeRequestStatusVertex>();
            for (BackOfficeRequestStatusVertex vertex : this.vertices) {
                this.statusMap.put(vertex.getStatus(), vertex);
            }
        }
        return this.statusMap;
    }

    /**
     * Returns if a system identifier is a leaf vertex.
     * 
     * @param systemIdentifier system identifier to be tested
     * @return if it's a leaf
     */
    public boolean isLeafVertex(BackOfficeRequestStatusSystemIdentifier systemIdentifier) {
        return this.getVertex(systemIdentifier).isLeaf();
    }

    /**
     * Returns the next vertex when a status is authorized.
     * 
     * @param from status before authorization.
     * @return the status after authorization.
     */
    public BackOfficeRequestStatusSystemIdentifier getOnAuthorization(BackOfficeRequestStatusSystemIdentifier from) {
        return this.getVertex(from).getAuthorizationEdge().getTo().getStatus();
    }

    /**
     * Returns the next vertex when a status is rejected.
     * 
     * @param from status before rejection.
     * @return the status after rejection.
     */
    public BackOfficeRequestStatusSystemIdentifier getOnRejection(BackOfficeRequestStatusSystemIdentifier from) {
        return this.getVertex(from).getRejectionEdge().getTo().getStatus();
    }

    /**
     * Finds the vertex in the map.
     * 
     * @param from system identifier.
     * @return vertex.
     */
    public boolean containsVertex(BackOfficeRequestStatusSystemIdentifier from) {
        return this.getStatusMap().containsKey(from);
    }

    /**
     * Finds the vertex in the map.
     * 
     * @param from system identifier.
     * @return vertex.
     */
    public BackOfficeRequestStatusVertex getVertex(BackOfficeRequestStatusSystemIdentifier from) {
        if (this.containsVertex(from)) {
            return this.getStatusMap().get(from);
        } else {
            throw new FrontException(FrontMessages.SYSTEM_ID_NOT_REGISTERED_IN_WORKFLOW.create(from));
        }
    }

    /**
     * @param from the system identifier.
     * @return the map from outcome to transition.
     */
    public Map<BackOfficeRequestRevisionOutcome, String> getTransitionLabelMap(BackOfficeRequestStatusSystemIdentifier from) {
        BackOfficeRequestStatusVertex vertex = this.getVertex(from);
        Map<BackOfficeRequestRevisionOutcome, String> output = new HashMap<BackOfficeRequestRevisionOutcome, String>();
        if (!this.isLeafVertex(from)) {
            output.put(BackOfficeRequestRevisionOutcome.REJECTED, vertex.getRejectionEdge().getName());
            output.put(BackOfficeRequestRevisionOutcome.AUTHORIZED, vertex.getAuthorizationEdge().getName());
        }
        return output;
    }

    /**
     * @return the rootStatus
     */
    public BackOfficeRequestStatusSystemIdentifier getRootStatus() {
        return this.rootStatus;
    }

}
